/*
 * @功能描述: 
 * @版本: v1.0.0
 * @作者: LuAn
 * @Date: 2021-08-30 19:58:46
 * @LastEditTime: 2021-09-03 05:41:04
 */
#include "bsp_gpio.h"
/**
 * @name: 
 * @msg: 
 * @param {GPIO_Type} *base
 * @param {int} pin
 * @param {gpio_pin_direction_t} dir
 * @param {int} out
 * @return {*}
 */
static void _gpio_init_2(GPIO_Type *base, int pin, gpio_pin_direction_t dir, int out)
{
  if (dir == kGPIO_DigitalInput)
  {

    base->GDIR &= ~(1 << pin);
  }
  else
  {

    base->GDIR |= (1 << pin);
    gpio_pinwrite(base, pin, out); /* 设置默认输出电平 */
  }
}
void gpio_init_pins_input(GPIO_Type *base, uint32_t pins)
{
  base->GDIR &= ~pins;
}

void gpio_init_pins_output(GPIO_Type *base, uint32_t pins)
{
  base->GDIR |= pins;
}
/**
 * @name: 
 * @msg: 
 * @param {GPIO_Type} *base
 * @param {int} pin
 * @return {*}
 */
void gpio_init_input(GPIO_Type *base, int pin)
{
  _gpio_init_2(base, pin, kGPIO_DigitalInput, 0);
}
/**
 * @name: 
 * @msg: 
 * @param {GPIO_Type} *base
 * @param {int} pin 指定第几pin脚
 * @param {int} level pin脚默认输出电平
 * @return {*}
 */
void gpio_init_output(GPIO_Type *base, int pin, int level)
{
  _gpio_init_2(base, pin, kGPIO_DigitalOutput, level);
}

/*
 * @description		: GPIO初始化。
 * @param - base	: 要初始化的GPIO组。
 * @param - pin		: 要初始化GPIO在组内的编号。
 * @param - config	: GPIO配置结构体。
 * @return 			: 无
 */
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
{
  if (config->direction == kGPIO_DigitalInput) /* 输入 */
  {
    base->GDIR &= ~(1 << pin);
  }
  else /* 输出 */
  {
    base->GDIR |= 1 << pin;
    gpio_pinwrite(base, pin, config->outputLogic); /* 设置默认输出电平 */
  }
}

/*
  * @description	 : 读取指定GPIO的电平值 。
  * @param - base	 : 要读取的GPIO组。
  * @param - pin	 : 要读取的GPIO脚号。
  * @return 		 : 无
  */
int gpio_pinread(GPIO_Type *base, int pin)
{
  return (((base->DR) >> pin) & 0x1);
}

/*
  * @description	 : 指定GPIO输出高或者低电平 。
  * @param - base	 : 要输出的的GPIO组。
  * @param - pin	 : 要输出的GPIO脚号。
  * @param - value	 : 要输出的电平，1 输出高电平， 0 输出低低电平
  * @return 		 : 无
  */
void gpio_pinwrite(GPIO_Type *base, int pin, int value)
{
  if (value == 0U)
  {
    base->DR &= ~(1U << pin); /* 输出低电平 */
  }
  else
  {
    base->DR |= (1U << pin); /* 输出高电平 */
  }
}
/**
 * @name: 
 * @msg: 为指定的 DR 位清 0
 * @param {GPIO_Type} *base
 * @param {uint32_t} pins, BSP_GPIO_PIN_0 .... BSP_GPIO_PIN_31
 * @return {*}
 */
void gpio_clr_pins(GPIO_Type *base, uint32_t pins)
{
  base->DR &= ~pins;
}
/**
 * @name: 
 * @msg: 为指定的 DR 置位 1 
 * @param {GPIO_Type} *base
 * @param {uint32_t} pins, BSP_GPIO_PIN_0 .... BSP_GPIO_PIN_31
 * @return {*}
 */
void gpio_set_pins(GPIO_Type *base, uint32_t pins)
{
  base->DR |= pins;
}

void gpio_int_init(GPIO_Type *base, uint32_t npin, gpio_interrupt_mode_t mode)
{
  if (mode == kGPIO_NoIntmode)
  {
    return;
  }
  if (mode == kGPIO_IntEdge) // 双边沿触发
  {
    base->EDGE_SEL |= (1 << npin);
    return;
  }
  __IO uint32_t *icr = &base->ICR1;
  int icr_shift = npin;
  if (npin >= 16)
  {
    icr = &base->ICR2;
    icr_shift -= 16;
  }
  icr_shift *= 2;
  base->EDGE_SEL &= ~(1 << npin); // 必须要清，如果是1的话 icr 的配置会被覆盖
  *icr &= (0x3 << icr_shift);
  *icr |= (mode << icr_shift);
}

/*
@  base: gpio结构体指针
@  pins: 可以使用 BSP_GPIO_PIN_0 ... BSP_GPIO_PIN_31 通过位或操作指定多个pins
@  ... : 不定参数，固定为 gpio_interrupt_mode_t 类型， pins中指定的多少个pins就有多少个 mode
*/
void gpio_pins_int_init(GPIO_Type *base, uint32_t pins, ...)
{
  // gpio_interrupt_mode_t mode = (gpio_interrupt_mode_t)va_arg(args, rt_int32_t);
  va_list args;
  va_start(args, pins);
  gpio_interrupt_mode_t mode = kGPIO_NoIntmode;
  int i = 0;
  for (i = 0; i < 32; i++)
  {
    if ((pins & (1 << i)) != 0)
    {
      mode = (gpio_interrupt_mode_t)va_arg(args, int);
      gpio_int_init(base, i, mode);
    }
  }
  va_end(args);
}
/*
@  base: gpio结构体指针
@  pins: 可以使用 BSP_GPIO_PIN_0 ... BSP_GPIO_PIN_31 通过位或操作指定多个pins
*/
void gpio_ints_enable(GPIO_Type *base, uint32_t pins)
{
  base->IMR |= pins;
}

/*
@  base: gpio结构体指针
@  pins: 可以使用 BSP_GPIO_PIN_0 ... BSP_GPIO_PIN_31 通过位或操作指定多个pins
*/
void gpio_ints_disable(GPIO_Type *base, uint32_t pins)
{
  base->IMR &= ~pins;
}
/*
* 清除中断标志位
*/
void gpio_clr_ints(GPIO_Type *base, uint32_t pins)
{
  base->ISR |= pins;
}
void io_pin_config(uint32_t muxRegister,
                   uint32_t muxMode,
                   uint32_t inputRegister,
                   uint32_t inputDaisy,
                   uint32_t configRegister,
                   uint32_t inputOnfield,
                   uint32_t configValue)
{
  IOMUXC_SetPinMux(muxRegister, muxMode, inputRegister, inputDaisy, configRegister, inputOnfield);
  IOMUXC_SetPinConfig(muxRegister, muxMode, inputRegister, inputDaisy, configRegister, configValue);
}